require('./util/test-init');
var AsyncVDOMBuilder = require('marko/runtime/vdom/AsyncVDOMBuilder');
var VElement = require('marko/runtime/vdom/VElement');
var expect = require('chai').expect;

function getChildNodes(parentNode) {
    var childNodes = [];

    var curChild = parentNode.___firstChild;
    while(curChild) {
        childNodes.push(curChild);
        curChild = curChild.___nextSibling;
    }

    return childNodes;
}
describe('AsyncVDOMBuilder', function() {
    it('sync', function() {
        var out = new AsyncVDOMBuilder();
        out.element('div', {}, 0);
        var tree = out.___getOutput();
        expect(getChildNodes(tree).length).to.equal(1);
    });

    it('end, then listen for finish', function(done) {
        var out = new AsyncVDOMBuilder();
        out.element('div', {}, 0);
        out.end();
        out.on('finish', function(result) {
            expect(getChildNodes(result.getOutput()).length).to.equal(1);
            done();
        });
    });

    it('async', function(done) {
        var out = new AsyncVDOMBuilder();
        out.element('div', {}, 0);
        var asyncOut = out.beginAsync();

        setTimeout(function() {
            asyncOut.element('span', {}, 0);
            asyncOut.end();
        }, 10);

        out.element('section', {}, 0);

        out.end();
        out.on('finish', function(result) {
            var tree = result.getOutput();
            expect(getChildNodes(tree).length).to.equal(3);
            expect(tree.___firstChild.___nodeName).to.equal('div');
            expect(tree.___firstChild.___nextSibling.___nodeName).to.equal('span');
            expect(tree.___firstChild.___nextSibling.___nextSibling.___nodeName).to.equal('section');
            done();
        });
    });

    it('promise', function(done) {
        const out = new AsyncVDOMBuilder();
        out.element('div', {}, 0);
        out.end().then((result) => {
            expect(getChildNodes(result.getOutput()).length).to.equal(1);
            done();
        }).catch(done);
    });

    it('async flush', function(done) {
        var out = new AsyncVDOMBuilder();
        out.on('update', function(result) {
            expect(getChildNodes(result.getOutput()).length).to.equal(1);
        });
        out.once('finish', function(result) {
            expect(getChildNodes(result.getOutput()).length).to.equal(2);
            done();
        });

        out.element('div', {}, 0);
        out.flush();

        var asyncOut = out.beginAsync();

        setTimeout(function() {
            asyncOut.element('span', {}, 0);
            asyncOut.end();
        }, 10);

        out.end();
    });

    it('for loop', function(done) {
        var out = new AsyncVDOMBuilder();
        out.once('finish', function(result) {
            var tree = result.getOutput();
            var childNodes = getChildNodes(tree);
            var header = childNodes[0];
            var list = childNodes[1];
            var paragraph = childNodes[2];
            expect(header.___nodeName).to.equal('h1');
            expect(list.___nodeName).to.equal('ul');
            expect(getChildNodes(list).length).to.equal(10);
            expect(paragraph.___nodeName).to.equal('p');
            done();
        });

        out.element('h1', {}, 0);

        out.beginElement('ul', {});

        for(var i = 0; i < 10; i++) {
            out.element('li', {}, 1).t(i);
        }

        out.endElement();

        out.element('p', {}, 0);

        out.end();
    });

    it('staticNode, text, comment', function(done) {
        var staticNode = new VElement('div', {}, 0, 'f891ea3');
        var out = new AsyncVDOMBuilder();

        out.node(staticNode);
        out.text('Hello <em>World</em>');
        out.comment('TODO: make this work');
        out.end();

        out.once('finish', function(result) {
            var tree = result.getOutput();
            var childNodes = getChildNodes(tree);
            expect(childNodes[0].___nodeName).to.equal('div');
            expect(childNodes[1].___nodeValue).to.equal('Hello <em>World</em>');
            expect(childNodes[2].___nodeValue).to.equal('TODO: make this work');
            done();
        });
    });

    // it('should handle timeouts correctly');
    //
    // it('should handle sync errors correctly');
    //
    // it('should handle timeout errors correctly');
    //
    // it('should avoid writes after end');
    //
    // it('globals');
});
